#ifndef __UDP_SERVER_HPP__
#define __UDP_SERVER_HPP__

#include "InetAddr.hpp"
#include "Comm.hpp"
#include <iostream>
#include <string>
#include <memory>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <functional>
#include <string.h>
#include "Log.hpp"
#include "User.hpp" 
#include "ThreadPool.hpp"

using namespace lyrics;
using namespace ThreadPoolModule;

const static int gsockfd = -1;
// 测试用的端口号
const static uint16_t defaultport = 8000;

using adduser_t = std::function<void(InetAddr& id)>;
using task_t = std::function<void()>;//这里是push给线程池的任务
using route_t = std::function<void(int sockfd,const std::string& message)>;//这里是线程池路由的方法
using remove_t = std::function<void(InetAddr &inet)>;//移除用户，用inetaddr直接移除用户


//防止UdpServer被拷贝
class nocopy
{
public:
nocopy();
    nocopy(const nocopy &) = delete;
    const nocopy& operator==(const nocopy &) = delete;
    ~nocopy();
};



//UdpServer是不会被拷贝的，所以继承上面delete所有拷贝的类
class UdpServer : public nocopy 
{
public:
    UdpServer(uint16_t port = defaultport)
     : _sockfd(gsockfd),_addr(port),_isrunning(false) {}
    // 1. 初始化服务器----都是套路---UDP初始化
    void InitServer()
    {
        // 创建套接字
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0); // IP？PORT？网络？本地？
        if (_sockfd < 0)
        {
            // 输出致命的错误
            LOG(LogLevel::FATAL) << "socket: " << strerror(errno);
            // 创建失败直接结束：
            Die(SOCKET_ERR);
        }
        LOG(LogLevel::INFO) << "socket success,sockfd is: " << _sockfd;

        int n = ::bind(_sockfd,_addr.NetAddr(), _addr.NetAddrLen());
        if(n < 0)
        {
            LOG(LogLevel::FATAL) <<"socket: " << strerror(errno);
            Die(BIND_ERR);
        }

        LOG(LogLevel::INFO) << "bind success";
    }
    //注册服务
    void RegisterService(adduser_t adduser,route_t route,remove_t removeuser)
    {
        _adduser = adduser;
        _route = route;
        _removeuser = removeuser;
    }
    void Start()
    {
        _isrunning = true;
        //服务器死循环
        while(true)
        {
            struct sockaddr_in peer;//远端
            socklen_t len = sizeof(peer); //必须设定
            char inbuffer[1024];
            ssize_t n = ::recvfrom(_sockfd,inbuffer,sizeof(inbuffer)-1,0,CONV(&peer),&len);
            //读取消息成功
            if(n > 0)
            {
                InetAddr cli(peer);
                //1. 需要知道消息内容
                inbuffer[n] = 0;
                std::string message;
                if(strcmp(inbuffer,"QUIT") == 0)
                {
                    //如何移除观察者？
                    _removeuser(cli);
                    //1. 删除用户,s删除用户之后，后面的消息需要告诉用户吗？----也是需要告诉所有人的，让所有人知道我走了
                    message = cli.Addr() + "#" + "我走了，你们聊";
                }
                else
                {
                    message = "[" + cli.Addr() + "]" + ":" + inbuffer;
                    //2. 新增用户
                    _adduser(cli);
                }
                task_t task = std::bind(UdpServer::_route,_sockfd,message);
                //3. 构建群发任务，推送给线程池，让线程池进行消息转发
                ThreadPool<task_t>::getInstance()->Equeue(task);

            }
        }
        _isrunning = false;
    }
    ~UdpServer()
    {
        if(_sockfd > gsockfd)
            ::close(_sockfd);
    }

private:
    int _sockfd;
    InetAddr _addr;
    bool _isrunning; // 服务器的运行状态
    //新增用户
    adduser_t _adduser;
    route_t _route;
    remove_t _removeuser;
};
#endif
